<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>[2.11]-核心思想：DI依赖注入-让资源更可控 | PhalApi(π框架) - PHP轻量级开源接口框架 - 助你创造价值！</title>
    <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
    <meta content="yes" name="apple-mobile-web-app-capable">
    <meta content="black" name="apple-mobile-web-app-status-bar-style">
    <meta content="telephone=no" name="format-detection">
    <meta content="email=no" name="format-detection">
    <meta name="Author" content="PhalApi,ecitlm,dogstar">
    <meta name="description" content="[2.11]-核心思想：DI依赖注入-让资源更可控，PhalApi是一个PHP轻量级开源接口框架，致力于快速开发接口服务。支持HTTP/SOAP/RPC等协议，可用于搭建接口/微服务/RESTful接口/Web Services。我们不断更新，保持生气；为接口负责，为开源负责！并承诺永久免费！">
    <meta name="keywords" content="PhalApi,phalapi,phalapi接口开发,后台接口开发,后台接口开发框架,接口开发,接口框架,开源接口框架,PHP后台接口开发,PHP接口开发,PHP接口框架,PHP后台接口框架,phalapi官网,PHP接口框架,php接口开发框架,php接口开发,php web框架,π框架,π开发框架,π接口框架,π接口开发框架,api接口,php接口,,PHP接口框架,phalapi文档,phalapi wiki,PhalApi文档,phalapi在线文档,phalapi官方文档">

    <link rel="stylesheet" type="text/css" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" media="screen">
    <link rel="stylesheet" type="text/css" href="https://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.css" media="screen">
    <link rel="stylesheet" href="../css/main.css" />
    <link rel="stylesheet" href="../css/loading_bar.css" />
    <link rel="icon" href="http://webtools.qiniudn.com/dog_catch.png" type="image/x-icon" />
    <script src="../js/pace.min.js"></script>
	
	<!-- 代码高亮 -->
	<link rel="stylesheet" href="../css/highlight.min.css">
	<script src="../js/highlight.min.js"></script>
	<script>hljs.initHighlightingOnLoad();</script>
    
</head>

<body>
    <!-- navbar start -->
    <div class="navbar navbar-default navbar-fixed-top" id="mainnav" role="navigation">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target=".navbar-collapse">
                    <span class="sr-only">Toggle navigation</span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                <a class="navbar-brand website_name" href="/"><!-- <span>PhalApi</span> --><strong></strong></a>
            </div>
            <div class="navbar-collapse collapse" aria-expanded="false" style="height: 1px;">
                <ul class="nav navbar-nav navbar-right" id="nav_bar">
                    <li><a href="https://www.phalapi.net/"><span class="glyphicon glyphicon-home"></span></a></li>
                    <li><a href="https://www.phalapi.net/download.html">下载</a></li>
                    <li class="active"><a href="https://www.phalapi.net/wikis/">文档</a></li>
                    <li><a href="https://www.phalapi.net/donate.html">贡献</a></li>
                    <li><a href="#">|</a></li>
                    <li><a href="http://qa.phalapi.net/" target="_blank">社区</a></li>
                    <li><a href="http://www.ituring.com.cn/book/2405" target="_blank">书籍</a></li>
                    <li><a href="http://demo.phalapi.net/listAllApis.php" target="_blank">体验</a></li>
                    <li><a href="https://github.com/phalapi/phalapi-library" target="_blank">扩展</a></li>
                </ul>
            </div>
            <!--/.nav-collapse -->
        </div>
    </div>
    <!-- navbar end -->


    <div id="content">
        <div class="container">
            <div class="row row-md-flex row-md-flex-wrap">
                <h4><a href="/wikis/%5B1.32%5D-%E5%9C%A8%E7%BA%BF%E6%8E%A5%E5%8F%A3%E6%96%87%E6%A1%A3%EF%BC%9A%E6%B3%A8%E9%87%8A%E8%A7%84%E8%8C%83.html">上一章</a>   <a href="/wikis/">文档首页</a>   <a href="/wikis/%5B2.12%5D-%E6%B5%B7%E9%87%8F%E6%95%B0%E6%8D%AE%EF%BC%9A%E5%8F%AF%E9%85%8D%E7%BD%AE%E7%9A%84%E5%88%86%E5%BA%93%E5%88%86%E8%A1%A8.html">下一章</a></h4>
<hr />
<p><em>一个没有绝对答案的世界，却拥有绝对的丰富。  --《沈奇岚：我愿生命从容》</em>  </p>
<h2>2.11.1 定义</h2>
<h3>(1) 关于依赖注入</h3>
<p>即控制反转，目的是了减少耦合性，简单来说就是使用开放式来获取需要的资源。</p>
<h3>(2) 关于资源</h3>
<p>这里说的资源主要是在开发过程中使用到的资源，包括配置项；数据库连接、Memcache、接口请求等系统级的服务；以及业务级使用到的实例等。</p>
<p>引入依赖注入的目的不仅是为了增加一个类，而是为了更好的对资源进行初始化、管理和维护。下面将进行详细的说明。  </p>
<h2>2.11.2 一个简单的例子</h2>
<p>很多时候，类之间会存在依赖、引用、委托的关系，如A依赖B时，可以这样使用：</p>
<pre><code class="language-php">class A {
    protected $b;

    public function __construct()
    {
        $this-&gt;b = new B();      
    }
}</code></pre>
<p>这种方式在A内限制约束了B的实例对象，当改用B的子类或者改变B的构建方式时，A需要作出调整。这时可以通过依赖来改善这种关系：</p>
<pre><code class="language-php">class A {
    protected $b;

    public function __construct($b)
    {
        $this-&gt;b = $b;       
    }
}</code></pre>
<p>再进一步，可以使用DI对B的对象进行管理：</p>
<pre><code class="language-php">class A {
    public function __construct()
    {       
    }

    public function doSth()
    {
        //当你需要使用B时
        $b = $di-&gt;get('B');
    }
}</code></pre>
<p>这样的好处？  </p>
<p>一方面，对于使用A的客户（指开发人员），不需要再添加一个B的成员变量，特别不是全部类的成员函数都需要使用B类服务时。另一方面在外部多次初始化A实例时，可以统一对B的构建。</p>
<h2>2.11.3 依赖注入的使用示例</h2>
<p>为方便使用，调用的方式有：set/get函数、魔法方法setX/getX、类变量$di-&gt;X、数组$di['X']，初始化的途径有：直接赋值、类名、匿名函数。</p>
<pre><code class="language-php">/** ------------------ 创建与设置 ------------------ **/
//获取DI
$di = DI();
//演示的key
$key = 'demoKey';

/** ------------------ 设置 ------------------ **/
//可赋值的类型：直接赋值、类名赋值、匿名函数
$di-&gt;set($key, 'Hello DI!');
$di-&gt;set($key, 'Simple');
$di-&gt;set($key, function(){
    return new Simple();
});
//设置途径：除了上面的set()，你还可以这样赋值
$di-&gt;setDemoKey('Hello DI!');
$di-&gt;demoKey = 'Hello DI!';
$di['demoKey'] = 'Hello DI!';

/** ------------------ 获取 ------------------ **/
//你可以这样取值
echo $di-&gt;get('demoKey'), "\n";
echo $di-&gt;getDemoKey(), "\n";
echo $di-&gt;demoKey, "\n";
echo $di['demoKey']. "\n";

/**
 * 演示类
 */
class Simple
{
    public function __construct()
    {
    }
}</code></pre>
<h2>2.11.4 依赖注入的好处</h2>
<h3>(1)减少对各个类编写工厂方法以单例获取的开发量</h3>
<p>DI相当于一个容器，里面可以放置基本的变量，也可以放置某类服务，甚至是像文件句柄这些的资源。在这容器里面，各个被注册的资源只会存在一份，也就是当被注册的资源为一个实例对象时，其效果就等于单例模式。  </p>
<p>因此，保存在DI里面的类，不需要再编写获取单例的代码，直接通过DI获取即可。  </p>
<p>例如很多API的服务组件以及其他的一些类，都实现了单例获取的方式。分别如：  </p>
<p>微博接口调用：  </p>
<pre><code class="language-php">&lt;?php
class Weibo_Api
{
    protected static $_instance = null;

    public static function getInstance()
    {
        if (!isset(self::$_instance)) {
            self::$_instance = new Weibo_Api();
        }
        return self::$_instance;
    }

    //....
}</code></pre>
<p>七牛云存储接口调用：</p>
<pre><code class="language-php">class Qiniu_Api {
    private static $_instance = null; //实例对象

    public static function getInstance()
    {
        if (self::$_instance ===null) {
            self::$_instance = new Qiniu_Api();
        }
        return self::$_instance;
    }
}</code></pre>
<p>QQ开放平台接口调用：</p>
<pre><code class="language-php">class QQ_Api { 
    private static $_instance = null; //实例对象

    public static function getInstance()
    {
        if (self::$_instance ===null) {
            self::$_instance = new QQ_Api();
        }
        return self::$_instance;
    }
}</code></pre>
<p>如果使用DI对上面这些服务进行管理，则上面三个类乃至其他的类对于单例这块的代码都可以忽略不写。注册代码如下：</p>
<pre><code class="language-php">$di-&gt;sStockApi = 'Weibo_Api';
$di-&gt;sDioAopi = 'Qiniu_Api';
$di-&gt;sShopApi = 'QQ_Api';</code></pre>
<p>上面是通过类名来进行延迟加载，但需要各个类提供public的无参数的构造函数。如果各个服务需要进行初始化，可以将初始化的工作放置在onInitialize()函数内，DI在对类实例化时会回调此函数进行初始化。</p>
<h3>(2)统一资源注册，便于后期维护管理</h3>
<p>这里引入DI，更多是为了“一处创建，多处使用”， 而不是各自创建，各自使用。</p>
<h4>创建和使用分离</h4>
<p>考虑以下场景：假设有这样的业务数据需要缓存机制，所以可注册一个实现缓存机制的实例：</p>
<pre><code class="language-php">$di-&gt;set('cache', new FileCache());</code></pre>
<p>然后提供给多个客户端使用：</p>
<pre><code class="language-php">$di['cache']-&gt;set('indexHtml', $indexContent);   //缓存页面
$di['cache']-&gt;set('config', $config);  //缓存公共配置
$di['cache']-&gt;set('artistList', $artistList);   //缓存数据</code></pre>
<p>当需要切换到MC或者Redis缓存或者多层缓存时，只需要修改对缓存机制的注入即可，如：</p>
<pre><code class="language-php">$di-&gt;set('cache', new RedisCache());</code></pre>
<p>依赖注入的一个很大的优势就在于可以推迟决策，当需要用到某个对象时，才对其实例化。可以让开发人员在一开始时不必要关注过多的细节实现，同时也给后期的扩展和维护带来极大的方便。  </p>
<p>再上一层，假设未来我们需要更高级的缓存服务，那么我们可以在不影响客户端使用的情况下，轻松升级。<br />
未来的可配置化的多级缓存策略</p>
<p>以下是一个模拟的使用场景，但依然对现在的项目有一定的帮助。假设我们现在有一个MC集群的缓存且引入了DI，使用如下：   </p>
<pre><code class="language-php">&lt;?php

//初始化
$di = PhalApi_DI::one();
$di-&gt;cache = new Memcache();
$di-&gt;cache-&gt;connect('localhost', 11211);

//不同文件的多处使用 ...
echo $di-&gt;cache-&gt;get('key');
echo $di-&gt;cache-&gt;get('key2');
echo $di-&gt;cache-&gt;get('key3');
...</code></pre>
<p>假设现在发现一层缓存存在穿透情况，为保证服务器的稳定性，我们已开发实现了多层缓存策略，并且可以通过简单配置即可实现，只需要对DI容器里面的cache实例进行升级，其他客户端的调用即可马上享受到缓存升级的优质服务。升级涉及改动的代码如下：</p>
<pre><code class="language-php">&lt;?php

//初始化
$di = new PhalApi_DI();
$di-&gt;cache = function () {
$ultraFastFrontend = new DataFrontend(array(
    "lifetime" =&gt; 3600
));

$fastFrontend = new DataFrontend(array(
    "lifetime" =&gt; 86400
));

$slowFrontend = new DataFrontend(array(
    "lifetime" =&gt; 604800
));

return new Multiple(array(
    new ApcCache($ultraFastFrontend, array(
        "prefix" =&gt; 'cache',
    )),
    new MemcacheCache($fastFrontend, array(
        "prefix" =&gt; 'cache',
        "host" =&gt; "localhost",
        "port" =&gt; "11211"
    )),
    new FileCache($slowFrontend, array(
        "prefix" =&gt; 'cache',
        "cacheDir" =&gt; "../app/cache/"
    ))
));
};</code></pre>
<p>备注：关于多级缓存策略，后续会提供源代码和重用库，或者期待读者的分享。</p>
<h3>(3)延迟式加载，提高性能</h3>
<p>延迟加载可以通过DI中的类名初始化、匿名函数和参数配置（未实现）三种方式来实现。  </p>
<p>延迟加载有时候是非常有必要的，如在初始化项目的配置时，随着配置项的数据增加，服务器的性能也将逐渐受到影响，因为配置的内容可能是硬编码，可能来自于数据库，甚至需要通过接口从后台调用获取， 特别当很多配置项不需要使用时。而此时，支持延时加载将可以达到很好的优化，而不用担心在需要使用的时候忘记了初始化。从而很好的提高服务器性能，提高响应速度。  </p>
<p>如对一些耗时的资源先进行匿名函数的初始化：   </p>
<pre><code class="language-php">$di['hightResource'] = function() {
    //获取返回耗性能的资源
    //return $resource; 
}</code></pre>
<h3>(4)以优雅的方式取代滥用的全局变量</h3>
<p>在我看来，PHP里面是不应该使用全局变量（global和$_GLOBALS），更不应该到处使用。  </p>
<p>用了DI来管理，即可这样注册：</p>
<pre><code class="language-php">$di-&gt;set('debug', true);</code></pre>
<p>然后这样使用：</p>
<pre><code class="language-php">$debug = $di-&gt;get('debug');</code></pre>
<p>也许有人会想：仅仅是换个地方存放变量而已吗？其实是换一种思想使用资源。  </p>
<p>以此延伸，DI还可用于改善优化另外两个地方：通过include文件途径对变量的使用和变量的多层传递。  </p>
<p>变量的多层传递，通俗来说就是漂洋过海的变量。  </p>
<h2>2.11.5 DI思想的来源与推荐参考</h2>
<p><a href="http://docs.phalconphp.com/en/latest/reference/di.html">Dependency Injection/Service Location</a></p>
<hr />
<h4><a href="/wikis/%5B1.32%5D-%E5%9C%A8%E7%BA%BF%E6%8E%A5%E5%8F%A3%E6%96%87%E6%A1%A3%EF%BC%9A%E6%B3%A8%E9%87%8A%E8%A7%84%E8%8C%83.html">上一章</a>   <a href="/wikis/">文档首页</a>   <a href="/wikis/%5B2.12%5D-%E6%B5%B7%E9%87%8F%E6%95%B0%E6%8D%AE%EF%BC%9A%E5%8F%AF%E9%85%8D%E7%BD%AE%E7%9A%84%E5%88%86%E5%BA%93%E5%88%86%E8%A1%A8.html">下一章</a></h4><div style="float: left">
<h4>
<a href="http://qa.phalapi.net/">还有疑问？欢迎到社区提问！</a>
&nbsp;&nbsp;
<a href="http://docs.phalapi.net/#/v2.0/">切换到PhalApi 2.x 开发文档。</a>
</h4>
</div>
            </div>
        </div>
    </div>

 <!-- 广告位 -->
<div class="grid-wrapper desktop-only">
	<p align="center">
		<a href="http://7xiz2f.com1.z0.glb.clouddn.com/%E6%88%91%E7%9A%84%E5%90%8D%E5%AD%97%E5%8F%AB%EF%BC%9A%CF%80%E6%A1%86%E6%9E%B6%20-%20PhalApi%202016%E5%B9%B4%E5%BA%A6%E5%BC%80%E6%BA%90%E6%80%BB%E7%BB%93%20-%20%E5%AE%98%E6%96%B9%E5%87%BA%E5%93%81.pdf" target="blank"><img width="950" height="100" src="http://7xiz2f.com1.z0.glb.clouddn.com/ad_20170104.png"></a>
		<a href="http://www.itran.cc/" target="blank"><img width="950" height="100" src="http://7xslqv.com1.z0.glb.clouddn.com/images/9/69/b88bc92455dc1239f9a5bf8d72929.png"></a>
		<a href="http://web-tools.phalapi.net/" target="blank"><img width="950" height="100" src="http://7xslqv.com1.z0.glb.clouddn.com/images/7/d0/88f523566c482296aecc43d185ca2.png"></a>
	</p>
</div>

        <!-- footer -->
        <div class="footer">
            <div class="link container ">
                <div class=" col-xs-7 col-sm-7 col-md-7 col-lg-7 ">
                    <h3>PhalApi (π框架)</h3>
                    <p>一个轻量级PHP开源接口框架，专注于接口服务开发，支持HTTP/SOAP/RPC协议，拥有自动生成的在线文档、多种开发语言的客户端SDK包以及可重用的扩展类库，可用于快速搭建微服务、RESTful接口或Web
                        Services。</p>
                    <!-- <p>:</p> -->
                    <a href="https://www.phalapi.net/" target="_blank"> PhalApi </a>
                    <span>|</span>
                    <a href="http://qa.phalapi.net/" target="_blank">社区</a>
                    <span>|</span>
                    <a href="download.html" target="_blank">下载</a>
                    <span>|</span>
                    <a href="/wikis/">文档</a>
                    <span>|</span>
                    <a href="http://www.ituring.com.cn/book/2405" target="_blank">书籍</a>
                    <span>|</span>
                    <a href="http://demo.phalapi.net/listAllApis.php" target="_blank">体验</a>
                    <span>|</span>
                    <a href="donate.html" target="_blank">贡献</a>
                    <span>|</span>
                    <a href="https://github.com/phalapi/phalapi-library" target="_blank">扩展</a>
                    <span>|</span>
                    <a href="/license.html" target="_blank">许可</a>
                    <span>|</span>
                    <a href="/about.html" target="_blank">关于</a>
                    <span>|</span>
                    <a href="https://www.phalapi.net/wikis/en/" target="_blank">English</a>

                </div>
                <div class=" col-xs-5 col-sm-5 col-md-5 col-lg-5 contact_us ">
                    <h3>联系我们</h3>
                    <a href="https://github.com/phalapi/phalapi"><img src="../images/github.png" alt="github" /></a>
                    <a href="http://weibo.com/p/100808d236e99beb645bfb56ed1c37dde9b8bd?k=phalapi%E5%BC%80%E6%BA%90%E6%A1%86%E6%9E%B6&from=501&_from_=huati_topic"><img src="../images/weibo.png"  alt="weibo" /></a>
                    <a href="http://7xslqv.com1.z0.glb.clouddn.com/images/1/b0/894fde762850cb11250253f7d5ede.png"><img src="../images/zfb.png"  alt="zfb" /></a>
					<a target="_blank" href="//shang.qq.com/wpa/qunwpa?idkey=f16292029e59975d4ccfccc70ed87aa5c5646df512e83b0e9e1270e8368be461"><img border="0" src="images/qq.png" alt="π框架 - PhalApi交流群②" title="π框架 - PhalApi交流群②"></a>
					<a href="http://git.oschina.net/dogstar/PhalApi"><img src="../images/git-oschina.png"  alt="git-oschina" /></a>
                </div>
                <div class="cls"></div>
                <div class="text-center copy_right"> ©2015-2017 PhalApi All Rights Reserved. <a href="http://www.miitbeian.gov.cn" target="_blank">粤ICP备15028808号</a>

				<script type="text/javascript">var cnzz_protocol = (("https:" == document.location.protocol) ? " https://" : " http://");document.write(unescape("%3Cspan id='cnzz_stat_icon_1255326144'%3E%3C/span%3E%3Cscript src='" + cnzz_protocol + "s4.cnzz.com/z_stat.php%3Fid%3D1255326144%26show%3Dpic' type='text/javascript'%3E%3C/script%3E"));</script>
                </div>
            </div>
        </div>
    </div>


    <a href="https://github.com/phalapi"><img id="gitHub_fllow" style="position: fixed; top: 0; right: 0; border: 0;z-index:9999" src="https://camo.githubusercontent.com/652c5b9acfaddf3a9c326fa6bde407b87f7be0f4/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f6f72616e67655f6666373630302e706e67" alt="Fork me on GitHub" data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_right_orange_ff7600.png"></a>


    <script src="../js/jquery-1.11.1.min.js"></script>
    <script src="../js/bootstrap.min.js"></script>
</body>

</html>